package com.wyz.socket.core.base.frame.send;

import com.wyz.socket.core.base.IoArgs;
import com.wyz.socket.core.base.packet.AbstractSendPacket;
import com.wyz.socket.core.base.frame.Frame;
import com.wyz.socket.core.base.packet.Packet;

import java.io.IOException;
import java.io.InputStream;
import java.nio.channels.Channels;
import java.nio.channels.ReadableByteChannel;

/**
 * 发送的首帧 , 除了标配的帧头 还有帧体的格式
 * 帧体
 * 5 byte 表示帧体携带数据的大小
 * 1 byte 表示该帧体的类型
 * 剩下的 存储 首帧的详情
 */
public class SendHeaderFrame extends AbstractSendPacketFrame {
    private final byte[] body;
    public static final int PACKET_HEADER_FRAME_MIN_LENGTH = 6;

    public SendHeaderFrame(short identifier, AbstractSendPacket<?> packet) {
        super(PACKET_HEADER_FRAME_MIN_LENGTH + (packet.getInfo() == null ? 0 : packet.getInfo().length), TYPE_HEADER, FLAG_NON, identifier, packet);

        int length = packet.length();
        byte type = packet.type();
        byte[] packetInfo = packet.getInfo();

        body = new byte[bodyRemaining];
        // 00000000 00000000 00000000 00000000 00000000 00000000
        // 最大上传的大小为 2147483647 字节 ~ 2047.9999990463MB ~ 2097151.9990234KB 约为2G大小
        // byte 0-4 size> 5  packet length
        body[0] = 0;
        body[1] = (byte) (length >> 24);
        body[2] = (byte) (length >> 16);
        body[3] = (byte) (length >> 8);
        body[4] = (byte) (length);
        // byte 5  size >1 packet type
        body[5] = type; // other

        if (packetInfo != null) {
            System.arraycopy(packetInfo, 0, body, PACKET_HEADER_FRAME_MIN_LENGTH, packetInfo.length);
        }
    }

    @Override
    protected int consumeBody(IoArgs args) throws IOException {
        int count = bodyRemaining;
        int offset = body.length - count;
        return args.readFrom(body, offset, count);
    }

    @Override
    protected Frame buildNextFrame() {
        byte type = sendPacket.type();
        short identifier = getBodyIdentifier();
        if (type == Packet.TYPE_STREAM_DIRECT) {
            int availabel = sendPacket.availabel();
            if (availabel == 0) {
                return new CancelSendFrame(identifier);
            }
            return new SendDirectEntityFrame(availabel, identifier, sendPacket, Channels.newChannel(sendPacket.open()));
        } else {
            return new SendEntityFrame(sendPacket.length(), identifier, sendPacket, Channels.newChannel(sendPacket.open()));
        }
    }
}
